/**
 * @(#)ApkProvinceServiceImpl.java 2016年11月12日
 * Copyright(C) 2016 ZHEXIN IT CO.,LTD. All rights reserved.
 */
package org.jsbd.boss.service.impl;

import org.apache.commons.lang.StringUtils;
import org.jsbd.boss.common.redis.RedisClient;
import org.jsbd.boss.dao.IApkLoginTypeDAO;
import org.jsbd.boss.dao.IChannelProvicneInfoDAO;
import org.jsbd.boss.dao.IDeviceConfigDAO;
import org.jsbd.boss.domian.ChannelProvinceInfo;
import org.jsbd.boss.domian.channel.*;
import org.jsbd.boss.enums.CarrierEnum;
import org.jsbd.boss.service.*;
import org.jsbd.boss.util.CacheKey;
import org.jsbd.boss.util.DateUtil;
import org.jsbd.boss.util.ProvinceUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

/**
 * apk省份配置
 * 
 * @author <a href="mailto:xupengcheng@zhexinit.com" >徐鹏程</a>
 * @version 1.0.0
 */
@Service
public class ApkProvinceServiceImpl implements IApkProvinceService {
	public static final Logger LOGGER = LoggerFactory.getLogger(ApkProvinceServiceImpl.class);
	@Resource
	private IChannelProvicneInfoDAO channelProvicneInfoDAO;

	@Resource(name = "newTaskService")
	private INewTaskService newTaskService;

	@Resource
	private SimulatorManager simulatorManager;

	@Resource
	private IApkSimulatorService apkSimulatorService;

	@Resource
	private ApkManager apkManager;

	@Resource
	private RedisClient redisClient;

	@Resource
	private IApkLoginTypeDAO apkLoginTypeDAO;

	@Resource
	private IDeviceConfigDAO deviceConfigDAO;

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jsbd.boss.service.IApkProvinceService#getProvinceByProvinceId(java
	 * .lang.String)
	 */
	@Override
	public List<ApkPRIConfig> getProvinceByProvinceId(int provinceId) {
		String cacheKey = CacheKey.APK_PROVINCE_CONFIG + provinceId;
		List<ApkPRIConfig> apkList = (List<ApkPRIConfig>) redisClient.get(cacheKey);
		if (apkList == null) {
			apkList = channelProvicneInfoDAO.getApkPRIConfigByProvinceId(provinceId);
			redisClient.put(cacheKey, apkList, 300);
		}
		return apkList;
	}

	@Override
	public List<ChannelProvinceInfo> getConfigByMark(String mark) {
		return channelProvicneInfoDAO.getConfigByMark(mark);
	}

	@Override
	@Transactional("transactionManagerCrack")
	public void updateProvinceByMark(String mark, String openProvince) {
		String[] provinceIds = openProvince.split(",");
		List<String> list = new ArrayList<String>();
		for (String provinceId : provinceIds) {
			list.add(provinceId);
			ChannelProvinceInfo channelProvinceInfo = new ChannelProvinceInfo();
			channelProvinceInfo.setMark(mark);
			channelProvinceInfo.setProvinceid(provinceId);
			try {
				channelProvicneInfoDAO.insertConfig(channelProvinceInfo);
			} catch (Exception e) {
				LOGGER.error("重复插入", e);
			}
		}
		ApkProvinceVo vo = new ApkProvinceVo();
		vo.setMark(mark);
		vo.setProvinceIds(list);
		channelProvicneInfoDAO.deleteApkProvinceConfigs(vo);
	}

	private Map<String, Integer> initApkNum(Set<String> apkSet) throws Exception {
		// 根据可用mark优先级排序，取量大于0的mark已经按优先级排序
		String[] apkArray = apkSet.toArray(new String[0]);
		Integer[] leftTaskNums = newTaskService.getLeftTaskNum(apkArray);
		Map<String, Integer> map = new HashMap<String, Integer>();
		for (int i = 0; i < apkArray.length; i++) {
			int total = leftTaskNums[i];
			if (total > 0) {
				String apk = apkArray[i];
				map.put(apk, total);
			}
		}
		return map;
	}

	private Map<String, List<ApkLoginTypeConfig>> initLoginTypeConfig(Map<String, Integer> map) {
		Map<String, List<ApkLoginTypeConfig>> apkLoginTypeMap = new HashMap<String, List<ApkLoginTypeConfig>>();
		for (String mark : map.keySet().toArray(new String[0])) {
			Object obj = apkLoginTypeDAO.selectApkLoginTypeConfig(mark);
			List<ApkLoginTypeConfig> list = (List<ApkLoginTypeConfig>) obj;
			long dayOfTime = DateUtil.getDaysOfTime();
			long leftTime = DateUtil.leftTimeToMidNight();
			String apkTaskKey = CacheKey.A_TASK + dayOfTime + mark;
			String key = CacheKey.APK_LOGIN_KEY + mark;
			List<ApkLoginTypeConfig> targetList = new ArrayList<>();
			if (list != null && list.size() > 0) {
				String total = redisClient.evalHget(apkTaskKey, "total");
				if (StringUtils.isBlank(total)) {
					continue;
				}
				Integer totalnum = Integer.parseInt(total);
				Integer loginTotalNum = 0;
				String loginKey = CacheKey.APK_LOGIN_KEY + dayOfTime + mark;
				// 数据库查询的过滤的占比以及按照登录方式排序
				for (ApkLoginTypeConfig loginConfig : list) {
					double rate = loginConfig.getRate();
					if (rate > 0 && totalnum > 0) {
						Integer loginType = loginConfig.getLoginType();
						String fieldKey = loginType + "total";
						String fieldExecKey = loginType + "exectotal";
						String execloginTotal = redisClient.evalHget(loginKey, fieldExecKey);
						int execTotal = 0;
						if (execloginTotal != null) {
							execTotal = Integer.parseInt(execloginTotal.toString());
						} else {
							redisClient.evalHincrby(loginKey, fieldExecKey, 0);
						}
						int loginTotal = (int) ((totalnum * rate / 100));
						loginTotalNum += loginTotal;
						redisClient.evalHset(loginKey, fieldKey, String.valueOf(loginTotal));
						int leftNum = loginTotal - execTotal;
						loginConfig.setLeftNum(leftNum);
						if (leftNum > 0) {
							targetList.add(loginConfig);
							LOGGER.info("apk|{}|loginType|{}|count|{}", new Object[] { mark, loginType, loginTotal });
						}
					}
				}
				int leftNum = totalnum - loginTotalNum;// 误差
				if (leftNum > 0 && targetList.size() > 0) {
					ApkLoginTypeConfig loginConfig = targetList.get(0);
					int loginTotal = (int) ((totalnum * loginConfig.getRate() / 100)) + leftNum;
					redisClient.evalHset(loginKey, loginConfig.getLoginType() + "total", String.valueOf(loginTotal));
				}
				if (targetList.size() > 0) {
					apkLoginTypeMap.put(mark, targetList);
					redisClient.put(key, targetList, (int) (leftTime / 1000));
				} else {
					redisClient.remove(key);
				}
				redisClient.expire(loginKey, leftTime);
			}
		}
		return apkLoginTypeMap;
	}


	private Map<Integer, String> getApkIdOfHsman(){
		List<ApkDevice> apkDevices = deviceConfigDAO.selectAllDevices();
		Map<Integer, String> map = new HashMap<>();

		for(ApkDevice apkDevice : apkDevices){
			map.put(apkDevice.getApkId(), apkDevice.getHsman());
		}

		return map;
	}

	@Override
	public void updateApksOfProvinces() {
		try {
			List<ApkSimulator> simulators = apkSimulatorService.getAllApkSimulators();
			Map<String, Boolean> apkSimMap = simulatorManager.getApkSimulators(simulators);
			Map<Integer, String> apkIdOfHsmanMap = getApkIdOfHsman();
			Set<String> apkSet = new HashSet<String>();
			Map<Integer, List<ApkPRIConfig>> provinceMap = new HashMap<Integer, List<ApkPRIConfig>>();
			String[] provinces = ProvinceUtils.getProvinceMap().keySet().toArray(new String[0]);
			for (String provinceStr : provinces) {
				int provine = Integer.parseInt(provinceStr);
				List<ApkPRIConfig> apkList = getProvinceByProvinceId(provine);
				if (apkList != null && apkList.size() > 0) {
					if (apkList != null && apkList.size() > 0) {
						for (ApkPRIConfig apk : apkList) {
							apkSet.add(apk.getMark());
						}
					}
					provinceMap.put(provine, apkList);
				}
			}
			Map<String, Integer> map = initApkNum(apkSet);
			Map<String, List<ApkLoginTypeConfig>> loginTypeMap = initLoginTypeConfig(map);
			for (String provinceStr : provinces) {
				int province = Integer.parseInt(provinceStr);
				List<ApkPRIConfig> apkList = provinceMap.get(province);
				List<ApkInfoVo> apks = new ArrayList<ApkInfoVo>();
				if (apkList != null && apkList.size() > 0) {
					for (int i = 0; i < apkList.size(); i++) {
						ApkPRIConfig apk = apkList.get(i);
						String mark = apk.getMark();
						// apk可用模拟器是否大于0
						Boolean exists = apkSimMap.get(mark);
						if(exists == null || !exists){
							continue;
						}
						List<ApkLoginTypeConfig> loginTypeList = loginTypeMap.get(mark);
						if (loginTypeList != null) {
							for (ApkLoginTypeConfig loginConfig : loginTypeList) {
								ApkInfoVo vo = new ApkInfoVo();
								vo.setMark(mark);
								vo.setBase(apk.getBase());
								vo.setApkId(apk.getId());
								vo.setApkName(apk.getApkName());
								String carrier = apk.getCarrier();
								if (StringUtils.isBlank(carrier)) {
									carrier = CarrierEnum.MOBILE.getType() + "";
								}
								vo.setCarrier(carrier);
								Integer installRate = apk.getInstallRate();
								if (installRate != null && installRate > 0) {
									vo.setIsReserve(true);
								} else {
									vo.setIsReserve(false);
								}
								vo.setLoginType(loginConfig.getLoginType());
								vo.setSysVer(loginConfig.getSysVer());
								vo.setMiguFlag(apk.getMiguFlag());
								vo.setAssignSysVer(apk.getAndriodVer());
								String hsman = apkIdOfHsmanMap.get(apk.getId());
								if(StringUtils.isNotBlank(hsman)){
									vo.setAssignDevice(hsman.toLowerCase());
								}else{
									vo.setAssignDevice(null);
								}
								apks.add(vo);
								LOGGER.info("省份 [{}] apk [{}]", province, mark);
							}
						}
					}
				}
				apkManager.addApksOfProvince(province, apks);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
